function [B,varargout] = nanUnique(A,varargin)
%nanUnique - Set unique, treating NaNs as equal
%   B = nanUnique(A) for the array A returns the same values as in A
%   but with no repetitions.  B will also be sorted (NaNs as last).
%
%   nanUnique(A,'rows') for the matrix A returns the unique rows
%   of A, treating NaNs as equal.
%
%   [B,I,J] = nanUnique(...) also returns index vectors I and J such
%   that B = A(I) and A = B(J) (or B = A(I,:) and A = B(J,:)).
%
%   [B,I,J] = nanUnique(...,'first') returns the vector I to
%   index the first occurrence of each unique value in A.
%   nanUnique(...,'last'), the default, returns the vector I to
%   index the last occurrence.
%
%   Example:
%     A = [1 2 NaN ; 1 2 NaN ; 1 2 NaN] ;
%     unique(A,'rows') 
%     % -> [1 2 NaN ; 1 2 NaN ; 1 2 NaN] ;
%     nanUnique(A,'rows') 
%     %->  [1 2 NaN]
%
%   For a cell array of strings, this function behaves exactly like UNIQUE.
%
%   See also UNIQUE, ISEQUALWITHNANS.

% for Matlab R13+
% version 2.0 (mar 2009)
% (c) Jos van der Geest
% email: jos@jasen.nl

% 1.0 (sep 2006) First release
% 2.0 (mar 2009) updated for recent ML releases that have a different
%      syntax of unique

if nargin > 1,
    try
        % check the additional arguments that are passed to UNIQUE
        unique(1,varargin{:}) ;
    catch
        msg = lasterr ;
        error([upper(mfilename) ':ErrorUsingUnique'],msg) ;
    end
end

if iscell(A) || ~any(isnan(A(:))),
    % for cell arrays place a call to unique.
    [B,varargout{1:nargout-1}] = unique(A,varargin{:}) ;
else
    q = isnan(A(:)) ;
    if sum(q) < 2,
        % for 0 or 1 NaN, unique will do
        [B,varargout{1:nargout-1}] = unique(A,varargin{:}) ;
    else
        % OK there are more than 1 NaNs    
        [C,C,C] = unique(A) ;     % convert every element of A to a unique number C, 
        C(isnan(A)) = max(C)+1 ;  % and give NaNs the same, but unique number
        
        C = reshape(C,size(A)) ;  % reshape back as A
        
        % Now do unique on C (all NaNs are now the same number)
        % and retrieve the index (and if requested, position as well)
        [B,B,varargout{2:nargout-1}] = unique(C,varargin{:}) ;       
        
        if nargout > 1,
            varargout{1} = B ; % index
            % varargout{2} is the position
        end
        
        if any(strcmpi('rows',varargin))
            B = A(B,:) ;  % unique rows
        else
            B = A(B) ;    % unique elements
        end
    end
end

